package tc.jv.task4;

import java.io.Serializable;
import java.util.Locale;

import tc.jv.task9.IncompatibleVectorSizeException;
import tc.jv.task9.VectorIndexOutOfBondsException;

/**
 * 
 * @author Vadim Gidulyan
 *
 */
public abstract class AbstractVector implements Vector, Serializable
{
	
	private static final long serialVersionUID = -2838015793684240783L;
	
	// SUPERCLASS METHODS

	@Override
	public Object clone()
	{
		try
		{
			return super.clone();
		}
		catch (CloneNotSupportedException e)
		{
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (obj == this)
			return true;
		if (obj instanceof Vector)
		{
			Vector v = (Vector) obj;
			if (this.size() == v.size())
			{	
				boolean e = true;
	
				for (int i = 0; e == true && i < size(); i++)
					e &= (this.get(i) == v.get(i));
				
				return e;
			}				
			else
				return false;
		}
		else
			return false;
	}

	@Override
	public int hashCode()
	{
		long lhc = 0;
		
		for (int i = 0; i < size(); i++)
			lhc ^= (long) get(i);
		
		int hc = (int) (lhc >> 32) ^ (int) lhc;
		
		return hc;
	}

	@Override
	public String toString()
	{
		String format = "%f\t";
		return formAString(format);
	}
	
	// METHODS
	
	@Override
	public String toString(int pcs)
	{
		String format = String.format("%%.%df\t", pcs); // %.<precision>f
		return formAString(format);
	}
	
	protected String formAString(String format)
	{
		String s = "";
		for (int i = 0; i < size(); i++)
			s = s + String.format(Locale.US, format, get(i));
		return s;
	}
	
	public void print()
	{
		System.out.println(toString());
	}
	
	public void print(int pcs)
	{
		System.out.println(toString(pcs));
	}
	
	public boolean fill(double[] array) throws IncompatibleVectorSizeException
	{
		return fill(array, 0);
	}

	public boolean fill(double[] array, int position) throws IncompatibleVectorSizeException
	{
		indexCheck(position + array.length - 1);
		
		for (int i = 0; i < array.length; i++)
			set(position+i, array[i]);
		
		return true;
	}
	
	public boolean fill(Vector v) throws IncompatibleVectorSizeException
	{
		return fill(v, 0);
	}
	
	public boolean fill(Vector v, int position) throws IncompatibleVectorSizeException
	{
		indexCheck(position + v.size() - 1);
		
		for (int i = 0; i < v.size(); i++)
			set(position+i, v.get(i));
		
		return true;
	}

	public boolean sum(Vector v) throws IncompatibleVectorSizeException
	{
		return sum(v, 0);
	}
	
	public boolean sum(Vector v, int position) throws IncompatibleVectorSizeException
	{
		indexCheck(position + v.size() - 1);
		
		for (int i = 0; i < v.size(); i++)
			set(position+i, get(i)+v.get(i));
		
		return true;
	}
	
	public boolean multiply(double multiplicator)
	{
		multiplicatorCheck(multiplicator);
		
		for (int i = 0; i < size(); i++)
			set(i, get(i)*multiplicator);
		
		return true;
	}
	
	// CHECKS
	
	protected boolean isValidMultiplicator(double multiplicator)
	{
		return !Double.isNaN(multiplicator) && !Double.isInfinite(multiplicator);
	}

	protected void multiplicatorCheck(double multiplicator)
	{
		if (!isValidMultiplicator(multiplicator))
			throw new IllegalArgumentException("Illegal multiplicator: " + multiplicator);
	}
	
	protected boolean isValidIndex(int index)
	{
		return index >= 0 && index < size();
	}
	
	protected void indexCheck(int index)
	{
		if (!isValidIndex(index))
			throw new VectorIndexOutOfBondsException(outOfBoundsMsg(index));
//            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}
	
	protected String outOfBoundsMsg(int index)
	{
        return "Index: " + index + ", Size: " + size();
    }

	protected void vectorArgumentCheck(double[] array, int position) 
			throws IncompatibleVectorSizeException
	{
		if (!isValidIndex(position + array.length - 1))
			throw new IncompatibleVectorSizeException(vectorSizeMsg(position, array.length));
	}
	
	protected void vectorArgumentCheck(Vector v, int position) 
										throws IncompatibleVectorSizeException
	{
		if (!isValidIndex(position + v.size() - 1))
			throw new IncompatibleVectorSizeException(vectorSizeMsg(position, v.size()));
	}
	
	protected String vectorSizeMsg(int position, int length)
	{
		return String.format("Position: %d, Length: %d (Size required: %d), Size: %d",
							  position, length, position+length, size());
	}
	
}
